/**
 * 
 */
package zeroj.web.dispatch;

import java.lang.reflect.Field;

import zeroj.orm.annotations.Transactional;
import zeroj.web.annotations.Action;
import zeroj.web.annotations.Form;
import zeroj.web.annotations.Interceptors;
import zeroj.web.annotations.LoginRequired;
import zeroj.web.annotations.Parameter;
import zeroj.web.annotations.Result;
import zeroj.web.annotations.Results;
import zeroj.web.core.ActionSupport;
import zeroj.web.core.Interceptor;
import zeroj.web.core.Scope;
import zeroj.web.interceptors.InterceptorFactory;
import zeroj.web.interceptors.LoginRequiredInterceptor;

/**
 * @author LYL(lylsir at gmail dot com)
 *
 */
final class ActionInfoParser {

	public static ActionInfo parse(final String basePackage, final Class<?> clz) {
		
		ActionInfo info = new ActionInfo();
		parseAction(basePackage, info, clz);
		parseResults(info, clz);
		parseTransaction(info, clz);
		parseLoginRequired(info, clz);
		parseInterceptors(info, clz);
		parseForms(info, clz);
		parseParameters(info, clz);
		return info;
	}
	
	private static void parseAction(String basePackage, ActionInfo ai, Class<?> clz) {
		
		String path = null;
		boolean getDirect = true;
		Scope scope = Scope.Request;
		if(clz.isAnnotationPresent(Action.class)) {
			Action action = clz.getAnnotation(Action.class);
			path = action.value();
			getDirect = action.directGet();
			scope = action.scope();
		} else {
			path = clz.getName().toLowerCase();
			if(path.endsWith("action"))
				path = path.substring(basePackage.length() + 1, path.length() - 6);
			else
				path = path.substring(basePackage.length() + 1);
		}
		ai.setPath(path);
		ai.setScope(scope);
		ai.setGetDirect(getDirect);
	}
	private static void parseResults(ActionInfo ai, Class<?> clz) {
		
		//predefined result
		ai.addResult(ActionSupport.ERROR, ai.getPath());
		ai.addResult(ActionSupport.INPUT, ai.getPath());
		ai.addResult(ActionSupport.SUCCESS, ai.getPath());
		if(clz.isAnnotationPresent(Result.class)) {
			
			Result result = clz.getAnnotation(Result.class);
			ai.addResult(result.key(), result.page());
		}
		if(clz.isAnnotationPresent(Results.class)) {
			
			Result[] results = clz.getAnnotation(Results.class).value();
			for(Result result : results) {
				
				ai.addResult(result.key(), result.page());
			}
		}
	}
	private static void parseTransaction(ActionInfo ai, Class<?> clz) {
		
		if(clz.isAnnotationPresent(Transactional.class))
			ai.setTransactional(true);
	}
	private static void parseLoginRequired(ActionInfo ai, Class<?> clz) {
		
		if(clz.isAnnotationPresent(LoginRequired.class)) {
			
			LoginRequired lr = clz.getAnnotation(LoginRequired.class);
			if(lr.role().length() > 0)
				ai.setLoginRole(lr.role());
			if(lr.loginUri().length() > 0)
				ai.setLoginUri(lr.loginUri());
			ai.setLoginRequired(true);
			ai.addInterceptor(InterceptorFactory.getInterceptor(LoginRequiredInterceptor.class));
		}

	}
	private static void parseInterceptors(ActionInfo ai, Class<?> clz) {
		
		if(clz.isAnnotationPresent(zeroj.web.annotations.Interceptor.class)) {
			
			Interceptor iterceptor = InterceptorFactory.getInterceptor(clz.getAnnotation(zeroj.web.annotations.Interceptor.class).value());
			if(iterceptor != null)
				ai.addInterceptor(iterceptor);
		}
		if(clz.isAnnotationPresent(Interceptors.class)) {
			
			zeroj.web.annotations.Interceptor[] ins = clz.getAnnotation(Interceptors.class).value();
			for(zeroj.web.annotations.Interceptor in : ins) {
				Interceptor iterceptor = InterceptorFactory.getInterceptor(in.value());
				ai.addInterceptor(iterceptor);
			}
		}

	}
	
	private static void parseForms(ActionInfo ai, Class<?> clz) {
		
		Field[] fields = clz.getFields();
		for(Field field : fields) {
			if(field.isAnnotationPresent(Form.class)) {
				parseForm(ai, field);
			}
		}
	}
	
	private static void parseForm(ActionInfo ai, Field field) {

		ai.addForm(field.getName(), field.getClass());
	}
	private static void parseParameters(ActionInfo ai, Class<?> clz) {
		
		Field[] fields = clz.getFields();
		for(Field field : fields) {
			if(field.isAnnotationPresent(Parameter.class)) {
				Parameter param = field.getAnnotation(Parameter.class);
				String name = param.name().length() == 0 ? field.getName() : param.name();
				ai.addParamName(param.index(), name);
			}
		}
	}
	
	
}
